package com.sky.wsp.jar.utils;

import org.springframework.beans.factory.config.YamlMapFactoryBean;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URL;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.*;
import java.util.function.Function;
import java.util.zip.ZipFile;

public class IOUtil {
    public static final long ONE_KB = 1024L;
    public static final long ONE_MB = 1048576L;
    public static final long FILE_COPY_BUFFER_SIZE = 31457280L;
    public static final int DEFAULT_BUFFER_SIZE = 524288;
    public static final int EOF = -1;

    private IOUtil() {
    }

    public static FileOutputStream openOutputStream(File file) throws IOException {
        return openOutputStream(file, false);
    }

    public static FileOutputStream openOutputStream(File file, boolean append) throws IOException {
        if (file.exists()) {
            if (file.isDirectory()) {
                throw new IOException("File '" + file + "' exists but is a directory");
            }

            if (!file.canWrite()) {
                throw new IOException("File '" + file + "' cannot be written to");
            }
        } else {
            File parent = file.getParentFile();
            if (parent != null && !parent.mkdirs() && !parent.isDirectory()) {
                throw new IOException("Directory '" + parent + "' could not be created");
            }
        }

        return new FileOutputStream(file, append);
    }

    public static FileInputStream openInputStream(File file) throws IOException {
        if (file.exists()) {
            if (file.isDirectory()) {
                throw new IOException("File '" + file + "' exists but is a directory");
            } else if (!file.canRead()) {
                throw new IOException("File '" + file + "' cannot be read");
            } else {
                return new FileInputStream(file);
            }
        } else {
            throw new FileNotFoundException("File '" + file + "' does not exist");
        }
    }

    public static long copyStream(InputStream input, OutputStream output) throws IOException {
        return copyStream(input, output, 9223372036854775807L);
    }

    public static long copyStream(InputStream input, OutputStream output, long total) throws IOException {
        byte[] buffer = new byte[524288];

        long count;
        int n;
        for (count = 0L; count < total && (n = input.read(buffer)) != -1; count += (long) n) {
            output.write(buffer, 0, n);
        }

        return count;
    }

    public static void deleteIfExist(File file) {
        if (file.exists()) {
            forceDelete(file);
        }

    }

    public static void forceDelete(File file) {
        if (file.isDirectory()) {
            try {
                deleteDirectory(file);
            } catch (IOException var3) {
                var3.printStackTrace();
            }
        } else {
            boolean filePresent = file.exists();
            if (!file.delete()) {
                if (!filePresent) {
                    return;
                }

                (new StringBuilder()).append("Unable to delete file: ").append(file).toString();
            }
        }

    }

    public static void deleteDirectory(File directory) throws IOException {
        if (directory.exists()) {
            if (!isSymlink(directory)) {
                cleanDirectory(directory);
            }

            if (!directory.delete()) {
                String message = "Unable to delete directory " + directory + ".";
                throw new IOException(message);
            }
        }
    }

    public static void cleanDirectory(File directory) throws IOException {
        String message;
        if (!directory.exists()) {
            message = directory + " does not exist";
            throw new IllegalArgumentException(message);
        } else if (!directory.isDirectory()) {
            message = directory + " is not a directory";
            throw new IllegalArgumentException(message);
        } else {
            File[] files = directory.listFiles();
            if (files == null) {
                throw new IOException("Failed to list contents of " + directory);
            } else {
                IOException exception = null;
                File[] var3 = files;
                int var4 = files.length;

                for (int var5 = 0; var5 < var4; ++var5) {
                    File file = var3[var5];
                    forceDelete(file);
                }

                if (null != exception) {
                    throw exception;
                }
            }
        }
    }

    public static boolean isSymlink(File file) throws IOException {
        if (file == null) {
            throw new NullPointerException("File must not be null");
        } else if (isSystemWindows()) {
            return false;
        } else {
            File fileInCanonicalDir = null;
            if (file.getParent() == null) {
                fileInCanonicalDir = file;
            } else {
                File canonicalDir = file.getParentFile().getCanonicalFile();
                fileInCanonicalDir = new File(canonicalDir, file.getName());
            }

            return !fileInCanonicalDir.getCanonicalFile().equals(fileInCanonicalDir.getAbsoluteFile());
        }
    }

    public static boolean isSystemWindows() {
        return File.separatorChar == '\\';
    }

    public static void closeQuietly(Closeable closeable) {
        try {
            if (closeable != null) {
                closeable.close();
            }
        } catch (IOException var2) {
        }

    }

    public static void closeQuietly(Socket closeable) {
        try {
            if (closeable != null && closeable.isConnected()) {
                closeable.close();
            }
        } catch (IOException var2) {
        }

    }

    public static void closeQuietly(ServerSocket closeable) {
        try {
            if (closeable != null) {
                closeable.close();
            }
        } catch (IOException var2) {
        }

    }

    public static void closeQuietly(ZipFile closeable) {
        try {
            if (closeable != null) {
                closeable.close();
            }
        } catch (IOException var2) {
        }

    }

    public static void moveDirectoryToDirectory(File src, File destDir, boolean createDestDir) throws IOException {
        if (src == null) {
            throw new NullPointerException("Source must not be null");
        } else if (destDir == null) {
            throw new NullPointerException("Destination directory must not be null");
        } else {
            if (!destDir.exists() && createDestDir) {
                destDir.mkdirs();
            }

            if (!destDir.exists()) {
                throw new FileNotFoundException("Destination directory '" + destDir + "' does not exist [createDestDir=" + createDestDir + "]");
            } else if (!destDir.isDirectory()) {
                throw new IOException("Destination '" + destDir + "' is not a directory");
            } else {
                moveDirectory(src, new File(destDir, src.getName()));
            }
        }
    }

    public static void moveFileToDirectory(File srcFile, File destDir, boolean createDestDir) throws IOException {
        if (srcFile == null) {
            throw new NullPointerException("Source must not be null");
        } else if (destDir == null) {
            throw new NullPointerException("Destination directory must not be null");
        } else {
            if (!destDir.exists() && createDestDir) {
                destDir.mkdirs();
            }

            if (!destDir.exists()) {
                throw new FileNotFoundException("Destination directory '" + destDir + "' does not exist [createDestDir=" + createDestDir + "]");
            } else if (!destDir.isDirectory()) {
                throw new IOException("Destination '" + destDir + "' is not a directory");
            } else {
                moveFile(srcFile, new File(destDir, srcFile.getName()));
            }
        }
    }

    public static void moveFile(File srcFile, File destFile) throws IOException {
        if (srcFile == null) {
            throw new NullPointerException("Source must not be null");
        } else if (destFile == null) {
            throw new NullPointerException("Destination must not be null");
        } else if (!srcFile.exists()) {
            throw new FileNotFoundException("Source '" + srcFile + "' does not exist");
        } else if (srcFile.isDirectory()) {
            throw new IOException("Source '" + srcFile + "' is a directory");
        } else if (destFile.isDirectory()) {
            throw new IOException("Destination '" + destFile + "' is a directory");
        } else {
            boolean rename = srcFile.renameTo(destFile);
            if (!rename) {
                copyFile(srcFile, destFile);
                if (!srcFile.delete()) {
                    System.out.println("Failed to delete original file '" + srcFile + "' after copy to '" + destFile + "'");
                }
            }

        }
    }

    public static void copyFile(File srcFile, File destFile) throws IOException {
        copyFile(srcFile, destFile, true);
    }

    public static void copyFile(File srcFile, File destFile, boolean preserveFileDate) throws IOException {
        if (srcFile == null) {
            throw new NullPointerException("Source must not be null");
        } else if (destFile == null) {
            throw new NullPointerException("Destination must not be null");
        } else if (!srcFile.exists()) {
            throw new FileNotFoundException("Source '" + srcFile + "' does not exist");
        } else if (srcFile.isDirectory()) {
            throw new IOException("Source '" + srcFile + "' exists but is a directory");
        } else if (srcFile.getCanonicalPath().equals(destFile.getCanonicalPath())) {
            throw new IOException("Source '" + srcFile + "' and destination '" + destFile + "' are the same");
        } else {
            File parentFile = destFile.getParentFile();
            if (parentFile != null && !parentFile.mkdirs() && !parentFile.isDirectory()) {
                throw new IOException("Destination '" + parentFile + "' directory cannot be created");
            } else if (destFile.exists() && !destFile.canWrite()) {
                throw new IOException("Destination '" + destFile + "' exists but is read-only");
            } else {
                doCopyFile(srcFile, destFile, preserveFileDate);
            }
        }
    }

    public static void moveDirectory(File srcDir, File destDir) throws IOException {
        if (srcDir == null) {
            throw new NullPointerException("Source must not be null");
        } else if (destDir == null) {
            throw new NullPointerException("Destination must not be null");
        } else if (!srcDir.exists()) {
            throw new FileNotFoundException("Source '" + srcDir + "' does not exist");
        } else if (!srcDir.isDirectory()) {
            throw new IOException("Source '" + srcDir + "' is not a directory");
        } else {
            boolean rename = srcDir.renameTo(destDir);
            if (!rename) {
                if (destDir.getCanonicalPath().startsWith(srcDir.getCanonicalPath())) {
                    throw new IOException("Cannot move directory: " + srcDir + " to a subdirectory of itself: " + destDir);
                }

                copyDirectory(srcDir, destDir);
                deleteDirectory(srcDir);
                if (srcDir.exists()) {
                    System.err.println("Failed to delete original directory '" + srcDir + "' after copy to '" + destDir + "'");
                }
            }

        }
    }

    public static void copyDirectory(File srcDir, File destDir) throws IOException {
        copyDirectory(srcDir, destDir, true);
    }

    public static void copyDirectory(File srcDir, File destDir, boolean preserveFileDate) throws IOException {
        copyDirectory(srcDir, destDir, (FileFilter) null, preserveFileDate);
    }

    public static void copyDirectory(File srcDir, File destDir, FileFilter filter, boolean preserveFileDate) throws IOException {
        if (srcDir == null) {
            throw new NullPointerException("Source must not be null");
        } else if (destDir == null) {
            throw new NullPointerException("Destination must not be null");
        } else if (!srcDir.exists()) {
            throw new FileNotFoundException("Source '" + srcDir + "' does not exist");
        } else if (!srcDir.isDirectory()) {
            throw new IOException("Source '" + srcDir + "' exists but is not a directory");
        } else if (srcDir.getCanonicalPath().equals(destDir.getCanonicalPath())) {
            throw new IOException("Source '" + srcDir + "' and destination '" + destDir + "' are the same");
        } else {
            List<String> exclusionList = null;
            if (destDir.getCanonicalPath().startsWith(srcDir.getCanonicalPath())) {
                File[] srcFiles = filter == null ? srcDir.listFiles() : srcDir.listFiles(filter);
                if (srcFiles != null && srcFiles.length > 0) {
                    exclusionList = new ArrayList(srcFiles.length);
                    File[] var6 = srcFiles;
                    int var7 = srcFiles.length;

                    for (int var8 = 0; var8 < var7; ++var8) {
                        File srcFile = var6[var8];
                        File copiedFile = new File(destDir, srcFile.getName());
                        exclusionList.add(copiedFile.getCanonicalPath());
                    }
                }
            }

            doCopyDirectory(srcDir, destDir, filter, preserveFileDate, exclusionList);
        }
    }

    private static void doCopyDirectory(File srcDir, File destDir, FileFilter filter, boolean preserveFileDate, List<String> exclusionList) throws IOException {
        File[] srcFiles = filter == null ? srcDir.listFiles() : srcDir.listFiles(filter);
        if (srcFiles == null) {
            throw new IOException("Failed to list contents of " + srcDir);
        } else {
            if (destDir.exists()) {
                if (!destDir.isDirectory()) {
                    throw new IOException("Destination '" + destDir + "' exists but is not a directory");
                }
            } else if (!destDir.mkdirs() && !destDir.isDirectory()) {
                throw new IOException("Destination '" + destDir + "' directory cannot be created");
            }

            if (!destDir.canWrite()) {
                throw new IOException("Destination '" + destDir + "' cannot be written to");
            } else {
                File[] var6 = srcFiles;
                int var7 = srcFiles.length;

                for (int var8 = 0; var8 < var7; ++var8) {
                    File srcFile = var6[var8];
                    File dstFile = new File(destDir, srcFile.getName());
                    if (exclusionList == null || !exclusionList.contains(srcFile.getCanonicalPath())) {
                        if (srcFile.isDirectory()) {
                            doCopyDirectory(srcFile, dstFile, filter, preserveFileDate, exclusionList);
                        } else {
                            doCopyFile(srcFile, dstFile, preserveFileDate);
                        }
                    }
                }

                if (preserveFileDate) {
                    destDir.setLastModified(srcDir.lastModified());
                }

            }
        }
    }

    private static void doCopyFile(File srcFile, File destFile, boolean preserveFileDate) throws IOException {
        if (destFile.exists() && destFile.isDirectory()) {
            throw new IOException("Destination '" + destFile + "' exists but is a directory");
        } else {
            FileInputStream fis = null;
            FileOutputStream fos = null;
            FileChannel input = null;
            FileChannel output = null;
            long pos = 0L;

            try {
                fis = new FileInputStream(srcFile);
                fos = new FileOutputStream(destFile);
                input = fis.getChannel();
                output = fos.getChannel();
                long size = input.size();

                for (long count = 0L; pos < size; pos += output.transferFrom(input, pos, count)) {
                    count = size - pos > 31457280L ? 31457280L : size - pos;
                }
            } finally {
                closeQuietly((Closeable) output);
                closeQuietly((Closeable) fos);
                closeQuietly((Closeable) input);
                closeQuietly((Closeable) fis);
            }

            if (srcFile.length() != pos) {
                throw new IOException("Failed to copy full contents from '" + srcFile + "' to '" + destFile + "'");
            } else {
                if (preserveFileDate) {
                    destFile.setLastModified(srcFile.lastModified());
                }

            }
        }
    }

    public static String toString(URL url, String encoding) throws IOException {
        InputStream inputStream = url.openStream();

        String var3;
        try {
            var3 = toString(inputStream, encoding);
        } finally {
            inputStream.close();
        }

        return var3;
    }

    public static String toString(InputStream input, String encoding) throws IOException {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        copyStream(input, bos);
        return bos.toString(encoding);
    }

    public static String readFile(File file) throws IOException {
        StringBuilder result = new StringBuilder();

        try {
            InputStreamReader isr = new InputStreamReader(Files.newInputStream(file.toPath()), StandardCharsets.UTF_8);
            Throwable var3 = null;

            try {
                BufferedReader bufferedReader = new BufferedReader(isr);
                Throwable var5 = null;

                try {
                    bufferedReader.lines().forEach((item) -> {
                        result.append(item).append("\r\n");
                    });
                } catch (Throwable var30) {
                    var5 = var30;
                    throw var30;
                } finally {
                    if (bufferedReader != null) {
                        if (var5 != null) {
                            try {
                                bufferedReader.close();
                            } catch (Throwable var29) {
                                var5.addSuppressed(var29);
                            }
                        } else {
                            bufferedReader.close();
                        }
                    }

                }
            } catch (Throwable var32) {
                var3 = var32;
                throw var32;
            } finally {
                if (isr != null) {
                    if (var3 != null) {
                        try {
                            isr.close();
                        } catch (Throwable var28) {
                            var3.addSuppressed(var28);
                        }
                    } else {
                        isr.close();
                    }
                }

            }
        } catch (IOException var34) {
            throw var34;
        }

        return result.toString();
    }

    public static void appendTailContent2File(String content, File targetFile) throws IOException {
        FileWriter writer = new FileWriter(targetFile, true);
        writer.write(content);
        writer.close();
    }

    public static void reWriteContent2File(String content, File targetFile) throws IOException {
        FileOutputStream fos = new FileOutputStream(targetFile);
        OutputStreamWriter osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8);
        osw.write(content);
        osw.close();
//        FileWriter writer = new FileWriter(targetFile);
//        writer.write(content);
//        writer.close();
    }

    public static Map<String, Object> customizeAppendContent2Yml(File configTemplateFile, File targetYmlFile) throws IOException {
        YamlMapFactoryBean yamlMapFactoryBean = new YamlMapFactoryBean();
        InputStreamResource isr = new InputStreamResource(Files.newInputStream(targetYmlFile.toPath()));
        yamlMapFactoryBean.setResources(new Resource[]{isr});
        Map<String, Object> targetYmlFileContent = yamlMapFactoryBean.getObject();
        Map<String, Object> transformTomcatKeyMap = transformTomcatKey(targetYmlFileContent);
        if (Objects.nonNull(System.getProperty("debugLog")) && "true".equals(System.getProperty("debugLog"))) {
            Iterator var6 = targetYmlFileContent.entrySet().iterator();

            while (var6.hasNext()) {
                Map.Entry<String, Object> entry = (Map.Entry) var6.next();
                System.out.println("key: " + (String) entry.getKey());
                System.out.println("value: " + entry.getValue());
            }
        }

        isr = new InputStreamResource(Files.newInputStream(configTemplateFile.toPath()));
        yamlMapFactoryBean.setResources(new Resource[]{isr});
        Map<String, Object> configTemplateFileContent = yamlMapFactoryBean.getObject();
        YamlUtils.addYamlMap(transformTomcatKeyMap, configTemplateFileContent);
        System.out.println("after merge yaml map...");
        if (Objects.nonNull(System.getProperty("debugLog")) && "true".equals(System.getProperty("debugLog"))) {
            Iterator var10 = transformTomcatKeyMap.entrySet().iterator();

            while (var10.hasNext()) {
                Map.Entry<String, Object> entry = (Map.Entry) var10.next();
                System.out.println("key: " + (String) entry.getKey());
                System.out.println("value: " + entry.getValue());
            }
        }

        return transformTomcatKeyMap;
    }

    public static boolean checkLibPath(List<String> fileList) {
        boolean result = true;
        boolean hasJar = false;
        Iterator var3 = fileList.iterator();

        String fileName;
        while (var3.hasNext()) {
            fileName = (String) var3.next();
            if (fileName.endsWith(".sh") || fileName.endsWith(".bat")) {
                result = false;
                break;
            }
        }

        var3 = fileList.iterator();

        while (var3.hasNext()) {
            fileName = (String) var3.next();
            if (fileName.endsWith(".jar")) {
                hasJar = true;
                break;
            }
        }

        return result & hasJar;
    }

    private static Map<String, Object> transformTomcatKey(Map<String, Object> yamlFileContentMap) {
        new HashMap();
        Map<String, Object> result = generalMapProcess(yamlFileContentMap, IOUtil::transFormTomcatKey);
        return result;
    }

    private static String transFormTomcatKey(String key) {
        String newKey = key;
        if (key.contains("tomcat")) {
            newKey = key.replaceAll("tomcat", "tongweb");
        }

        return newKey;
    }

    private static Map<String, Object> generalMapProcess(Map<String, Object> map, Function<String, String> keyFunc) {
        Map<String, Object> resultMap = new HashMap();
        map.forEach((key, value) -> {
            String newkey = (String) keyFunc.apply(key);
            if (!(value instanceof List)) {
                if (value instanceof Map) {
                    Map<String, Object> subResultMap = generalMapProcess((Map) value, keyFunc);
                    resultMap.put(newkey, subResultMap);
                } else {
                    resultMap.put(keyFunc.apply(key), value);
                }
            }

        });
        return resultMap;
    }

    public static String createConfigYaml(Map<String, Object> configContent, String filePath) {
        System.out.println("createConfigYaml ,path is : " + filePath);
        DumperOptions options = new DumperOptions();
        options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
        Yaml yaml = new Yaml(options);
        String str = yaml.dump(configContent);
        str = YamlUtils.formatYamlStr(str);

        try {
            FileWriter fw = new FileWriter(filePath);
            fw.write(str);
            fw.flush();
            fw.close();
            System.out.println("生成yaml完成");
        } catch (IOException var6) {
            var6.printStackTrace();
        }

        return str;
    }
}
